<?php

abstract class ZMBootstrap 
{
	/**
	 * @var PHP_Exceptionizer
	 */
	protected $_exceptionizer;
	
	
	/**
	 * Центр входа в инициализацию. Должен быть определен внутри приложения.
	 * 
	 * @return void
	 */
	abstract public function execute();
	
	/**
	 * Переопределение настроек php для локальной копии проекта.
	 * Берет из config.ini директиву php и расценивает значения оттуда
	 * как параметры для ini_set.
	 * 
	 * Корректно работает с составными директивами, например:
	 * [php]
	 * session.save_handler = 'memcached' 
	 *
	 * @return void
	 */
	protected function _initIni()
	{
		$phpSettings = Config::getInstance()->php;
		if (!$phpSettings) {
			return ;
		}

		$phpSettings = $phpSettings->toArray();
		foreach ($phpSettings as $key => $value) {
			if (is_array($value)) {
				foreach ($value as $k => $v) {
					ini_set($key . '.' . $k, $v);
				}
			} else {
				ini_set($key, $value);
			}
		}
	}
	
	/**
	 * Обеспечивает хранение сессий в memcache, если установлен нужный save_handler.
	 * 
	 * Внутри функции мы проходим по всем включенным серверам в конфиге, 
	 * пытаемся подключиться к ним, запоминаем все сервера к которым подключение удалось.
	 * И устанавливаем в session.save_path все живые сервера.
	 * 
	 * Чтобы это работало, нужно включить директиву session.save_handler = memcache, 
	 * и желательно в config.ini проекта. 
	 * 
	 * Потому как если делать это в php.ini глобально - мы рискнуем столкнуться с 
	 * неприятностями при отключении этой функции, когда в кластере окажется мертвый сервер. 
	 * 
	 * @return void
	 */
	protected function _initMemcachedSessionHandler()
	{
		if (ini_get('session.save_handler') != 'memcache') {
			return;
		}
		
		$backend = Cache_Manager::getInstance()->getBackend();
		if (!$backend instanceof Cache_Backend_Memcached) {
			return;
		}
		
		$savePath = '';
		$memcache = new Memcache();
		$servers = Cache_Manager::getInstance()->getConfig()->cache_backend->options->servers;
		foreach ($servers as $server) {
			if (!@$memcache->connect($server->host, $server->port, 1)) continue;
			if ($savePath) $savePath .= ',';
			$savePath .= "tcp://{$server->host}:{$server->port}?persistent=1";
		}
		
		ini_set('session.save_path', $savePath);
	}
	
	/**
	 * Преобразование всех ошибок php в Exception. В дальнейшем они могли бы красиво выводиться с трейсбэком
	 * на отладочной странице.
	 * 
	 * @link http://dklab.ru/lib/PHP_Exceptionizer/
	 * @return void
	 */
	protected function _initPHPExceptionizer()
	{
		$this->_exceptionizer = new PHP_Exceptionizer(E_ALL);
	}
	
	/**
	 * Включаем отладочную консоль ZFDebug, когда мы находимся в отладочном режиме.
	 * 
	 * @link http://code.google.com/p/zfdebug/
	 * @return void
	 */
	protected function _initZFDebug()
	{
		// Do not init in production mode
		if (!Debug::getInstance()->isDebugMode()) {
			return;
		}
		
		// Detect ajax-mode and not use ZFDebug
		if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])
			&& $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
			$this->_initFirePhp();
			return ;
		}

		// Dont use ZFDebug in CLI Application
		if (empty($_SERVER['DOCUMENT_ROOT'])) {
			return ;
		}

		$options = array(
			'jquery_path' => 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js',
		    'plugins' => array(
		    	'Variables',
		        //'Html',
		        'Memory',
				//'Time',
		        //'Registry',
		        //'Cache' => array('backend' => Cache_Manager::getInstance()->getCleanBackend()),
			)
		);

		$debug = new Debug_ControllerPlugin($options);

		// Register custom error handler plugin
		$exception = new Debug_ControllerPlugin_Exception();
		$debug->registerPlugin($exception);

		// Get Db adapter
		$adapter = Db::getConnection();
		// In Debug mode we storage all statement
		$adapter->setStatementClass('Db_Statement');

		// Register custom db logger plugin
		$db = new Debug_ControllerPlugin_Database(array($adapter));
		$debug->registerPlugin($db);

		// Register custom file plugin
		$file = new Debug_ControllerPlugin_File(array('base_path' => BASE_DIR));
		$debug->registerPlugin($file);

		// Register custom time plugin
		// Tempolary disable. Work strange.
		// $time = new Debug_ControllerPlugin_Time();
		// $debug->registerPlugin($time);

		// Register debug plugin in FrontController
		$frontController = Zend_Controller_Front::getInstance();
		$frontController->registerPlugin($debug);
	}
	
	/**
	 * Включает вывод запросов к БД в firebug.
	 * Активируется из функции _initZFDebug автоматически при ajax-запросах.
	 * 
	 * @link http://www.firephp.org/
	 * @return void
	 */
	protected function _initFirePhp() {
		$profiler = new Zend_Db_Profiler_Firebug('All DB Queries');
		$profiler->setEnabled(true);
		$db = Db::getInstance()->getConnection();
		$db->setProfiler($profiler);
	}
}